/*
    GNU GENERAL LICENSE
    Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2016 Lobo Evolution

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public
    License as published by the Free Software Foundation; either
    verion 3 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General License for more details.

    You should have received a copy of the GNU General Public
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    

    Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it
 */
package org.lobobrowser.html.control;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.ImageObserver;
import java.net.MalformedURLException;
import java.net.URL;

import javax.swing.SwingUtilities;

import org.apache.batik.transcoder.TranscoderException;
import org.lobobrowser.html.HtmlAttributeProperties;
import org.lobobrowser.html.dombl.ImageEvent;
import org.lobobrowser.html.dombl.ImageListener;
import org.lobobrowser.html.dombl.SVGRasterizer;
import org.lobobrowser.html.domimpl.HTMLBaseInputElement;
import org.lobobrowser.html.domimpl.HTMLElementImpl;
import org.lobobrowser.html.renderer.HtmlController;
import org.lobobrowser.html.renderer.RElement;
import org.lobobrowser.html.renderer.RenderableSpot;
import org.lobobrowser.html.style.HtmlValues;
import org.lobobrowser.util.gui.WrapperLayout;

/**
 * The Class InputImageControl.
 */
public class InputImageControl extends BaseInputControl implements ImageListener {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 1L;

	/** The valign. */
	private int valign = RElement.VALIGN_BASELINE;

	/** The preferred size. */
	private Dimension preferredSize;

	/** The declared width. */
	private int declaredWidth;

	/** The declared height. */
	private int declaredHeight;

	/** The image. */
	private Image image;

	/** The mouse being pressed. */
	private boolean mouseBeingPressed;

	/** The alt. */
	private String alt;

	/**
	 * Instantiates a new input image control.
	 *
	 * @param modelNode
	 *            the model node
	 */
	public InputImageControl(final HTMLBaseInputElement modelNode) {
		super(modelNode);
		this.setLayout(WrapperLayout.getInstance());
		alt = modelNode.getAlt();
		modelNode.addImageListener(this);
		this.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent e) {
				mouseBeingPressed = true;
				repaint();
			}

			@Override
			public void mouseReleased(MouseEvent e) {
				mouseBeingPressed = false;
				repaint();
				HtmlController.getInstance().onPressed(modelNode, e, e.getX(), e.getY());
			}
		});

		if (modelNode.getSrc().contains("svg")) {

			try {
				URL u = new URL(modelNode.getSrc());
				SVGRasterizer r = new SVGRasterizer(u);
				image = r.bufferedImageToImage();

			} catch (MalformedURLException | TranscoderException e1) {
				e1.printStackTrace();
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
	 */
	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Dimension size = this.getSize();
		Insets insets = this.getInsets();
		Image image = this.image;
		if (image != null) {
			g.drawImage(image, insets.left, insets.top, size.width - insets.left - insets.right,
					size.height - insets.top - insets.bottom, this);
		} else {
			g.drawString(alt, 10, 10);
		}
		if (this.mouseBeingPressed) {
			Color over = new Color(255, 100, 100, 64);
			if (over != null) {
				Color oldColor = g.getColor();
				try {
					g.setColor(over);
					g.fillRect(0, 0, size.width, size.height);
				} finally {
					g.setColor(oldColor);
				}
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.lobobrowser.html.control.BaseInputControl#reset(int, int)
	 */
	@Override
	public void reset(int availWidth, int availHeight) {
		super.reset(availWidth, availHeight);
		HTMLElementImpl element = this.controlElement;
		String width = element.getAttribute(HtmlAttributeProperties.WIDTH);
		String height = element.getAttribute(HtmlAttributeProperties.HEIGHT);
		int dw = HtmlValues.getPixelSize(width, null,-1,availWidth);
		int dh = HtmlValues.getPixelSize(height, null,-1,availHeight);
		this.declaredWidth = dw;
		this.declaredHeight = dh;
		this.preferredSize = this.createPreferredSize(dw, dh);
		int valign;
		String alignText = element.getAttribute(HtmlAttributeProperties.ALIGN);
		if (alignText == null) {
			valign = RElement.VALIGN_BASELINE;
		} else {
			alignText = alignText.toLowerCase().trim();
			if ("middle".equals(alignText)) {
				valign = RElement.VALIGN_MIDDLE;
			} else if ("absmiddle".equals(alignText)) {
				valign = RElement.VALIGN_ABSMIDDLE;
			} else if ("top".equals(alignText)) {
				valign = RElement.VALIGN_TOP;
			} else if ("bottom".equals(alignText)) {
				valign = RElement.VALIGN_BOTTOM;
			} else if ("baseline".equals(alignText)) {
				valign = RElement.VALIGN_BASELINE;
			} else if ("absbottom".equals(alignText)) {
				valign = RElement.VALIGN_ABSBOTTOM;
			} else {
				valign = RElement.VALIGN_BASELINE;
			}
		}
		this.valign = valign;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#getPreferredSize()
	 */
	@Override
	public Dimension getPreferredSize() {
		Dimension ps = this.preferredSize;
		return ps == null ? new Dimension(0, 0) : ps;
	}

	/**
	 * Creates the preferred size.
	 *
	 * @param dw
	 *            the dw
	 * @param dh
	 *            the dh
	 * @return the dimension
	 */
	public Dimension createPreferredSize(int dw, int dh) {
		Image img = this.image;
		if (dw == -1) {
			dw = img == null ? -1 : img.getWidth(this);
			if (dw == -1) {
				dw = 0;
			}
		}
		if (dh == -1) {
			dh = img == null ? -1 : img.getHeight(this);
			if (dh == -1) {
				dh = 0;
			}
		}
		return new Dimension(dw, dh);
	}

	/**
	 * Check preferred size change.
	 *
	 * @return true, if successful
	 */
	private final boolean checkPreferredSizeChange() {
		Dimension newPs = this.createPreferredSize(this.declaredWidth, this.declaredHeight);
		Dimension ps = this.preferredSize;
		if (ps == null) {
			return true;
		}
		if ((ps.width != newPs.width) || (ps.height != newPs.height)) {
			this.preferredSize = newPs;
			return true;
		} else {
			return false;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int,
	 * int)
	 */
	@Override
	public boolean imageUpdate(Image img, int infoflags, int x, int y, final int w, final int h) {
		if (((infoflags & ImageObserver.ALLBITS) != 0) || ((infoflags & ImageObserver.FRAMEBITS) != 0)) {
			if (SwingUtilities.isEventDispatchThread()) {
				if (!checkPreferredSizeChange()) {
					repaint();
				} else {
					if (ruicontrol != null) {
						ruicontrol.preferredSizeInvalidated();
					}
				}
			} else {
				SwingUtilities.invokeLater(new Runnable() {
					@Override
					public void run() {
						if (!checkPreferredSizeChange()) {
							repaint();
						} else {
							if (ruicontrol != null) {
								ruicontrol.preferredSizeInvalidated();
							}
						}
					}
				});
			}
		}
		return true;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.Component#imageUpdate(java.awt.Image, int, int, int, int,
	 * int)
	 */
	/**
	 * Image update.
	 *
	 * @param img
	 *            the img
	 * @param w
	 *            the w
	 * @param h
	 *            the h
	 */
	public void imageUpdate(Image img, final int w, final int h) {
		if (SwingUtilities.isEventDispatchThread()) {
			if (!checkPreferredSizeChange()) {
				repaint();
			} else {
				if (ruicontrol != null) {
					ruicontrol.preferredSizeInvalidated();
				}
			}
		} else {
			SwingUtilities.invokeLater(new Runnable() {
				@Override
				public void run() {
					if (!checkPreferredSizeChange()) {
						repaint();
					} else {
						if (ruicontrol != null) {
							ruicontrol.preferredSizeInvalidated();
						}
					}
				}
			});
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.lobobrowser.html.control.BaseInputControl#paintSelection(java.awt.
	 * Graphics , boolean, org.lobobrowser.html.renderer.RenderableSpot,
	 * org.lobobrowser.html.renderer.RenderableSpot)
	 */
	@Override
	public boolean paintSelection(Graphics g, boolean inSelection, RenderableSpot startPoint, RenderableSpot endPoint) {
		return inSelection;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.lobobrowser.html.dombl.ImageListener#imageLoaded(org.lobobrowser.html
	 * .dombl.ImageEvent)
	 */
	@Override
	public void imageLoaded(ImageEvent event) {
		// Implementation of ImageListener. Invoked in a request thread most
		// likely.
		Image image = event.image;
		// ImageIcon imageIcon = new ImageIcon(image);
		// this.button.setIcon(imageIcon);
		this.image = image;
		int width = image.getWidth(this);
		int height = image.getHeight(this);
		if ((width != -1) && (height != -1)) {
			this.imageUpdate(image, width, height);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.lobobrowser.html.dombl.InputContext#resetInput()
	 */
	@Override
	public void resetInput() {
		// NOP
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.lobobrowser.html.control.BaseInputControl#getVAlign()
	 */
	@Override
	public int getVAlign() {
		return this.valign;
	}
}
